#!/usr/bin/env python3
"""
MinIO 命令行接口

提供命令行方式访问 MinIO 对象存储，支持文件上传、下载、列表、删除等操作。

使用示例：
    # 初始化存储桶
    minio-cli init
    
    # 上传文件
    minio-cli upload --bucket datasets --project yolo-project --file /path/to/video.mp4
    minio-cli upload -b deploy -p msf -f local_cache/ -r --pattern "*.mp4"

    # 下载文件
    minio-cli download --bucket models --project yolo-project --file best.pt --output ./models/
    minio-cli download -b deploy -p msf -r --pattern "*.mp4" -o ./local_cache/
    
    # 列出文件
    minio-cli list --bucket datasets --project yolo-project
    
    # 删除文件
    minio-cli delete --bucket results --project yolo-project --file output.txt
"""

import argparse
import sys
from pathlib import Path
from typing import Optional, List
from .client import MinIOClient


def get_available_buckets() -> List[str]:
    """从配置文件获取可用的存储桶类型
    
    Returns:
        可用的存储桶类型列表
    """
    try:
        client = MinIOClient()
        return list(client.buckets.keys())
    except Exception as e:
        # 如果配置加载失败，返回默认值
        print(f"警告: 无法加载配置文件，使用默认存储桶类型: {e}", file=sys.stderr)
        return ['datasets', 'models', 'results']


def init_command(args):
    """初始化存储桶"""
    client = MinIOClient()
    success = client.init_buckets()
    return 0 if success else 1


def upload_command(args):
    """上传文件或目录"""
    client = MinIOClient()
    
    # 检查文件/目录路径
    file_path = args.file
    path = Path(file_path)
    
    if not path.exists():
        print(f"✗ 路径不存在: {file_path}")
        return 1
    
    # 如果是目录，使用批量上传
    if path.is_dir():
        if not args.recursive:
            print(f"✗ {file_path} 是目录，请使用 -r 或 --recursive 参数进行递归上传")
            return 1
        
        # 批量上传目录
        pattern = args.pattern if args.pattern else "*"
        result = client.upload_directory(
            bucket_type=args.bucket,
            project_name=args.project,
            local_dir_path=file_path,
            remote_dir_prefix=args.prefix if args.prefix else "",
            pattern=pattern,
            recursive=True,
            show_progress=not args.no_progress
        )
        
        return 0 if result['success'] > 0 else 1
    else:
        # 单文件上传
        remote_filename = args.name if args.name else path.name
        
        success = client.upload_file(
            bucket_type=args.bucket,
            project_name=args.project,
            local_file_path=file_path,
            remote_filename=remote_filename,
            show_progress=not args.no_progress
        )
        
        return 0 if success else 1


def download_command(args):
    """下载文件或目录"""
    client = MinIOClient()
    
    # 如果指定了递归模式，批量下载
    if args.recursive:
        output_dir = args.output if args.output else "."
        pattern = args.pattern if args.pattern else "*"
        
        result = client.download_directory(
            bucket_type=args.bucket,
            project_name=args.project,
            local_dir_path=output_dir,
            remote_dir_prefix=args.prefix if args.prefix else "",
            pattern=pattern,
            show_progress=not args.no_progress
        )
        
        return 0 if result['success'] > 0 else 1
    else:
        # 单文件下载
        if not args.file:
            print("✗ 请指定要下载的文件名（-f/--file）")
            return 1
        
        # 确定本地保存路径
        if args.output:
            output_path = Path(args.output)
            if output_path.is_dir():
                # 如果是目录，使用远程文件名
                output_path = output_path / args.file
            local_file_path = str(output_path)
        else:
            # 默认保存到当前目录
            local_file_path = args.file
        
        success = client.download_file(
            bucket_type=args.bucket,
            project_name=args.project,
            remote_filename=args.file,
            local_file_path=local_file_path,
            show_progress=not args.no_progress
        )
        
        return 0 if success else 1


def list_command(args):
    """列出文件"""
    client = MinIOClient()
    
    objects = client.list_objects(
        bucket_type=args.bucket,
        project_name=args.project if args.project else None
    )
    
    if not objects:
        print(f"未找到文件")
        return 0
    
    print(f"\n存储桶: {args.bucket}")
    if args.project:
        print(f"项目: {args.project}")
    print(f"共找到 {len(objects)} 个文件:\n")
    
    # 打印表头
    print(f"{'文件名':<60} {'大小':<15} {'最后修改时间':<25}")
    print("-" * 100)
    
    # 打印文件列表
    for obj in objects:
        size_str = format_size(obj['size'])
        time_str = obj['last_modified'].strftime('%Y-%m-%d %H:%M:%S')
        # 简化文件名显示（去掉环境前缀）
        display_name = obj['name']
        print(f"{display_name:<60} {size_str:<15} {time_str:<25}")
    
    return 0


def delete_command(args):
    """删除文件"""
    client = MinIOClient()
    
    # 确认删除（除非指定了 --yes）
    if not args.yes:
        response = input(f"确认要删除 {args.bucket}/{args.project}/{args.file} 吗？(y/N): ")
        if response.lower() != 'y':
            print("取消删除")
            return 0
    
    success = client.delete_object(
        bucket_type=args.bucket,
        project_name=args.project,
        remote_filename=args.file
    )
    
    return 0 if success else 1


def info_command(args):
    """获取文件信息"""
    client = MinIOClient()
    
    info = client.get_object_info(
        bucket_type=args.bucket,
        project_name=args.project,
        remote_filename=args.file
    )
    
    if info is None:
        print(f"✗ 文件不存在: {args.bucket}/{args.project}/{args.file}")
        return 1
    
    print(f"\n文件信息:")
    print(f"  名称: {info['name']}")
    print(f"  大小: {format_size(info['size'])}")
    print(f"  最后修改: {info['last_modified'].strftime('%Y-%m-%d %H:%M:%S')}")
    print(f"  ETag: {info['etag']}")
    print(f"  内容类型: {info['content_type']}")
    
    return 0


def format_size(size_bytes: int) -> str:
    """格式化文件大小
    
    Args:
        size_bytes: 字节数
        
    Returns:
        格式化后的大小字符串
    """
    for unit in ['B', 'KB', 'MB', 'GB', 'TB']:
        if size_bytes < 1024.0:
            return f"{size_bytes:.2f} {unit}"
        size_bytes /= 1024.0
    return f"{size_bytes:.2f} PB"


def main():
    """主函数"""
    # 动态获取可用的存储桶类型
    available_buckets = get_available_buckets()
    
    parser = argparse.ArgumentParser(
        description='MinIO 对象存储命令行工具',
        formatter_class=argparse.RawDescriptionHelpFormatter,
        epilog=__doc__
    )
    
    subparsers = parser.add_subparsers(dest='command', help='可用命令')
    
    # init 命令
    parser_init = subparsers.add_parser('init', help='初始化存储桶')
    parser_init.set_defaults(func=init_command)
    
    # upload 命令
    parser_upload = subparsers.add_parser('upload', help='上传文件或目录')
    parser_upload.add_argument('-b', '--bucket', required=True,
                              choices=available_buckets,
                              help='存储桶类型')
    parser_upload.add_argument('-p', '--project', required=True,
                              help='项目名称')
    parser_upload.add_argument('-f', '--file', required=True,
                              help='本地文件或目录路径')
    parser_upload.add_argument('-n', '--name',
                              help='远程文件名（仅用于单文件上传）')
    parser_upload.add_argument('-r', '--recursive', action='store_true',
                              help='递归上传目录（类似 cp -r）')
    parser_upload.add_argument('--pattern',
                              help='文件匹配模式，支持通配符（如 "*.mp4", "*.txt"）')
    parser_upload.add_argument('--prefix',
                              help='远程目录前缀')
    parser_upload.add_argument('--no-progress', action='store_true',
                              help='不显示进度条')
    parser_upload.set_defaults(func=upload_command)
    
    # download 命令
    parser_download = subparsers.add_parser('download', help='下载文件或批量下载')
    parser_download.add_argument('-b', '--bucket', required=True,
                                choices=available_buckets,
                                help='存储桶类型')
    parser_download.add_argument('-p', '--project', required=True,
                                help='项目名称')
    parser_download.add_argument('-f', '--file',
                                help='远程文件名（单文件下载时必需）')
    parser_download.add_argument('-o', '--output',
                                help='本地保存路径（文件或目录）')
    parser_download.add_argument('-r', '--recursive', action='store_true',
                                help='批量下载（类似 cp -r）')
    parser_download.add_argument('--pattern',
                                help='文件匹配模式，支持通配符（如 "*.mp4", "*.txt"）')
    parser_download.add_argument('--prefix',
                                help='远程目录前缀')
    parser_download.add_argument('--no-progress', action='store_true',
                                help='不显示进度条')
    parser_download.set_defaults(func=download_command)
    
    # list 命令
    parser_list = subparsers.add_parser('list', help='列出文件')
    parser_list.add_argument('-b', '--bucket', required=True,
                            choices=available_buckets,
                            help='存储桶类型')
    parser_list.add_argument('-p', '--project',
                            help='项目名称（不指定则列出所有项目）')
    parser_list.set_defaults(func=list_command)
    
    # delete 命令
    parser_delete = subparsers.add_parser('delete', help='删除文件')
    parser_delete.add_argument('-b', '--bucket', required=True,
                              choices=available_buckets,
                              help='存储桶类型')
    parser_delete.add_argument('-p', '--project', required=True,
                              help='项目名称')
    parser_delete.add_argument('-f', '--file', required=True,
                              help='远程文件名')
    parser_delete.add_argument('-y', '--yes', action='store_true',
                              help='跳过确认提示')
    parser_delete.set_defaults(func=delete_command)
    
    # info 命令
    parser_info = subparsers.add_parser('info', help='获取文件信息')
    parser_info.add_argument('-b', '--bucket', required=True,
                            choices=available_buckets,
                            help='存储桶类型')
    parser_info.add_argument('-p', '--project', required=True,
                            help='项目名称')
    parser_info.add_argument('-f', '--file', required=True,
                            help='远程文件名')
    parser_info.set_defaults(func=info_command)
    
    # 解析参数
    args = parser.parse_args()
    
    if not args.command:
        parser.print_help()
        return 1
    
    # 执行命令
    try:
        return args.func(args)
    except KeyboardInterrupt:
        print("\n\n操作已取消")
        return 130
    except Exception as e:
        print(f"\n✗ 错误: {e}")
        import traceback
        traceback.print_exc()
        return 1


if __name__ == '__main__':
    sys.exit(main())

